package com.xcode.example.modules.imgcompress.controller;

import com.xcode.example.base.BaseController;
import com.xcode.example.common.result.AjaxResult;
import com.xcode.example.config.AppConfig;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 图片压缩controller
 * @author Administrator
 */
@Controller
@RequestMapping("/img/compress")
@Slf4j
public class ImgCompressController extends BaseController {

    /**
     * 打开页面
     * @return 页面地址
     */
    @RequestMapping("compressPage")
    public String compressPage() {
        return "imgcompress/imgcompress";
    }

    /**
     * 上传图片并进行压缩处理
     * @return 页面地址
     */
    @RequestMapping("/uploadAndCompress")
    @ResponseBody
    public AjaxResult uploadAndCompress(MultipartFile file) {
        if (file != null && file.getSize() > 0) {
            AjaxResult result = AjaxResult.success();
            Map<String, String> imgs = new HashMap<>(5);

            String fileName = file.getOriginalFilename() == null ? "" : file.getOriginalFilename();
            // 获取文件扩展名
            String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
            //如果文件不是图片，则不上传
            if (!"jpg".equalsIgnoreCase(ext) && !"jpeg".equalsIgnoreCase(ext)
                    && !"png".equalsIgnoreCase(ext) && !"gif".equalsIgnoreCase(ext)
                    && !"bmp".equalsIgnoreCase(ext)) {
                return AjaxResult.error("图片格式不正确");
            }

            //文件重命名
            fileName = UUID.randomUUID().toString() + "." + ext;

            //文件上传至指定目录
            String outputDirectory = AppConfig.getUploadPath();

            //原图保存
            String imgUrl = uploadFile(file, outputDirectory, fileName);
            if (StringUtils.isNotBlank(imgUrl)) {
                imgs.put("原图", imgUrl);

                //按像素压缩
                String compressByPixelDirectory = AppConfig.getUploadPath() + "compress/";
                File outputDirectoryFile = new File(compressByPixelDirectory);
                if (!outputDirectoryFile.exists()) {
                    //创建目录
                    if (!outputDirectoryFile.mkdirs()) {
                        return null;
                    }
                }

                String compressByPixelFileName = UUID.randomUUID().toString() + "." + ext;
                //将图片压缩到500*500以内
                compressByPixel(outputDirectory + fileName,
                        compressByPixelDirectory + compressByPixelFileName, 500, 500);

                imgs.put("按像素压缩", AppConfig.getResourcePath() + "/compress/" + compressByPixelFileName);


                //按文件大小压缩
                String compressBySizeDirectory = AppConfig.getUploadPath() + "compress/";
                outputDirectoryFile = new File(compressBySizeDirectory);
                if (!outputDirectoryFile.exists()) {
                    //创建目录
                    if (!outputDirectoryFile.mkdirs()) {
                        return null;
                    }
                }

                String compressBySizeFileName = UUID.randomUUID().toString() + "." + ext;

                //将图片压缩到100Kb
                compressBySize(outputDirectory + fileName,
                        compressBySizeDirectory + compressBySizeFileName, 1f, 100 * 1024);

                imgs.put("按大小压缩", AppConfig.getResourcePath() + "/compress/" + compressBySizeFileName);
            }

            result.put("imgs", imgs);
            return result;
        }
        return AjaxResult.error("未选择文件");
    }

    /**
     * 按图片尺寸循环压缩，直到合适大小
     * @param srcPath 源文件路径
     * @param destPath 目标文件路径
     * @param quality 压缩质量
     * @param compSize 压缩后的目标文件最大尺寸
     */
    private void compressBySize(String srcPath, String destPath, float quality, long compSize) {
        try {
            //scale设置为1，表示像素保持不变
            //指定图片
            Thumbnails.of(srcPath).scale(1).outputQuality(quality).toFile(destPath);
        } catch (IOException e) {
            if (log.isDebugEnabled()) {
                e.printStackTrace();
            }
            log.error("按尺寸压缩图片失败：{}", e.getMessage());
            return ;
        }
        File thumbFile = new File(destPath);
        // 大于最大值，再次压缩，且保证quality不能小于0
        if (thumbFile.length() > compSize && quality > 0.2) {
            // 删除刚产生的压缩文件
            thumbFile.delete();

            //每次图片的质量-10%，循环进行压缩直至大小符合条件
            quality = quality - 0.1f;
            if (quality <= 0) {
                return ;
            }
            compressBySize(srcPath, destPath, quality, compSize);
        }
    }

    /**
     * 按图片像素压缩：保持图片的宽高比
     * @param srcPath 源文件路径
     * @param destPath 目标文件路径
     * @param maxWidth 压缩后的最大宽度
     * @param maxHeight 压缩后的目标文件最大尺寸
     */
    private void compressByPixel(String srcPath, String destPath, int maxWidth, int maxHeight) {
        try {
            Thumbnails.of(srcPath).size(maxWidth,maxHeight).toFile(destPath);
        } catch (IOException e) {
            if (log.isDebugEnabled()) {
                e.printStackTrace();
            }
            log.error("按像素压缩图片失败：{}", e.getMessage());
        }
    }
}
